﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Mvc;
using ExtendedMvc.Html;

namespace ExtendedMvc.Elements {
	/// <summary>
	/// Builds grid commands
	/// </summary>
	public class GridCommandBuilder<TModel> : ICollection<IGridCommandBase<TModel>>
		where TModel : class {
		private readonly List<IGridCommandBase<TModel>> _commands = new List<IGridCommandBase<TModel>>();
		private IModelViewHelper<IEnumerable<TModel>> _helper;
		private ModelMetadata _metadata;
		private Expression<Func<TModel, object>> _keyExpression;

		public GridCommandBuilder(IModelViewHelper<IEnumerable<TModel>> helper, Expression<Func<TModel, object>> keyExpression) {
			_helper = helper;
			_metadata = _helper.GetMetadataForType(typeof(TModel));
			_keyExpression = keyExpression;
		}

		public IGridCommandBase<TModel> ForDataRow(string text, string link) {
			var command = new GridCommand<TModel>(_helper, text, link).DisplayIn(GridCommandPosition.DataRow);
			Add(command);
			return command;
		}

		public GridActionCommand<TModel> ForDataRowAsAction(string text, string actionName, string controllerName = null) {
			var command = new GridActionCommand<TModel>(_helper, text, actionName, controllerName).DisplayIn(GridCommandPosition.DataRow);
			Add(command);
			return command;
		}

		public GridRouteCommand<TModel> ForDataRowAsRoute(string text, string routeName, string protocol = null, string hostName = null, string fragment = null) {
			var command = new GridRouteCommand<TModel>(_helper, text, routeName, protocol, hostName, fragment).DisplayIn(GridCommandPosition.DataRow);
			Add(command);
			return command;
		}

		public IGridCommandBase<TModel> ForHeader(string text, string link) {
			var command = new GridCommand<TModel>(_helper, text, link).DisplayIn(GridCommandPosition.Header);
			Add(command);
			return command;
		}

		public IGridCommandBase<TModel> ForHeaderAsAction(string text, string actionName, string controllerName = null) {
			var command = new GridActionCommand<TModel>(_helper, text, actionName, controllerName).DisplayIn(GridCommandPosition.Header);
			Add(command);
			return command;
		}

		public IGridCommandBase<TModel> ForHeaderAsRoute(string text, string routeName, string protocol = null, string hostName = null, string fragment = null) {
			var command = new GridRouteCommand<TModel>(_helper, text, routeName, protocol, hostName, fragment).DisplayIn(GridCommandPosition.Header);
			Add(command);
			return command;
		}

		protected IList<IGridCommandBase<TModel>> Commands {
			get { return _commands; }
		}

		///// <summary>
		///// Specifies that a custom command should be constructed with the specified name.
		///// </summary>
		///// <param name="name"></param>
		//public IGridColumn<TModel> For(string name) {
		//    var command = new GridColumn<TModel>(x => string.Empty, name, null);
		//    Add(command);
		//    return command.Partial(name);
		//}

		public IEnumerator<IGridCommandBase<TModel>> GetEnumerator() {
			return _commands.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}


		protected virtual void Add(IGridCommandBase<TModel> command) {
			_commands.Add(command);
		}

		void ICollection<IGridCommandBase<TModel>>.Add(IGridCommandBase<TModel> command) {
			Add(command);
		}

		void ICollection<IGridCommandBase<TModel>>.Clear() {
			_commands.Clear();
		}

		bool ICollection<IGridCommandBase<TModel>>.Contains(IGridCommandBase<TModel> command) {
			return _commands.Contains(command);
		}

		void ICollection<IGridCommandBase<TModel>>.CopyTo(IGridCommandBase<TModel>[] array, int arrayIndex) {
			_commands.CopyTo(array, arrayIndex);
		}

		bool ICollection<IGridCommandBase<TModel>>.Remove(IGridCommandBase<TModel> command) {
			return _commands.Remove(command);
		}

		int ICollection<IGridCommandBase<TModel>>.Count {
			get { return _commands.Count; }
		}

		bool ICollection<IGridCommandBase<TModel>>.IsReadOnly {
			get { return false; }
		}
	}
}
